﻿using DNFImagePacks2Manager.Controls;
using DNFImagePacks2Manager.NPK;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Windows.Graphics.Imaging;
using Windows.Media.Core;

namespace DNFImagePacks2Manager.Helpers
{
    // NPK助手
    public sealed partial class NPKHelper
    {
        // DNF官方音频文件正则
        [GeneratedRegex(@"^sounds[a-z0-9_\-.()&']*\.NPK$", RegexOptions.IgnoreCase, "zh-CN")]
        private static partial Regex SoundOfficialRegex();

        // DNF官方NPK正则
        [GeneratedRegex(@"^sprite[a-z0-9_\-.()&']*\.NPK$", RegexOptions.IgnoreCase, "zh-CN")]
        private static partial Regex ImageOfficialRegex();

        // NPK文件正则
        [GeneratedRegex(@"^.+(\.npk|\.npk\.disable)$", RegexOptions.IgnoreCase, "zh-CN")]
        private static partial Regex NPKFileRegex();


        private static readonly byte[] IMG_ENCRYPT_FLAG;

        static NPKHelper()
        {
            byte[] bytes = new byte[256];
            string decryptString = "puchikon@neople dungeon and fighter ";
            byte[] decryptBytes = Encoding.ASCII.GetBytes(decryptString);
            int len = decryptBytes.Length;
            Array.Copy(decryptBytes, 0, bytes, 0, len);
            for (int i = len; i < 255; ++i)
            {
                switch ((i - len) % 3)
                {
                    case 0:
                        bytes[i] = 68; // 'D'
                        break;
                    case 1:
                        bytes[i] = 78; // 'N'
                        break;
                    case 2:
                        bytes[i] = 70; // 'F'
                        break;
                }
            }
            bytes[255] = 32; // ' '
            IMG_ENCRYPT_FLAG = bytes;
        }


        // 合法文件名检查
        public static bool FilenameCheckImage(string name)
        {
            return FilenameCheckNPKFile(name) && !FilenameCheckImageOfficial(name);
        }

        public static bool FilenameCheckSound(string name)
        {
            return FilenameCheckNPKFile(name) && !FilenameCheckSoundOfficial(name);
        }

        // 检查是否是DNF官方NPK文件
        public static bool FilenameCheckImageOfficial(string name)
        {
            return ImageOfficialRegex().IsMatch(name);
        }

        public static bool FilenameCheckSoundOfficial(string name)
        {
            return SoundOfficialRegex().IsMatch(name);
        }

        // 检查是否是NPK文件
        public static bool FilenameCheckNPKFile(string name)
        {
            return NPKFileRegex().IsMatch(name);
        }

        public static string DecryptIMGName(byte[] encryptBytes)
        {
            try
            {
                byte[] bytes = new byte[256];
                byte[] decryptBytes = IMG_ENCRYPT_FLAG;
                for (int i = 0; i < 256; ++i)
                {
                    bytes[i] = (byte)(encryptBytes[i] ^ decryptBytes[i]);
                }
                string fullString = Encoding.UTF8.GetString(bytes);
                int nullIndex = fullString.IndexOf('\0');
                if (nullIndex >= 0)
                {
                    return fullString[..nullIndex];
                }
                else
                {
                    return fullString;
                }
            }
            catch (Exception)
            {
                return "";
            }
        }

        /*
         * 0: 未知
         * 1: 图像
         * 2: 音频
         */
        public static int GetNPKType(Stream stream)
        {
            using var reader = new BinaryReader(stream);
            NPKHeader header = new(reader);
            int count = header.Count;
            if (header.ValidateFlag() && count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    NPKIndex index = new(reader);
                    string imgName = index.Name;
                    if (imgName.Contains(".img"))
                    {
                        return 1;
                    }
                    if (imgName.Contains(".ogg"))
                    {
                        return 2;
                    }
                }
            }
            return 0;
        }

        public static int GetNPKType(string path)
        {
            if (!File.Exists(path))
                return 0;

            try
            {
                using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
                int type = GetNPKType(fileStream);
                return type;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        public static void PreviewNPK(Page page, string name, string path)
        {
            if (!File.Exists(path))
                return;
            int type = GetNPKType(path);
            switch (type)
            {
                case 1:
                    PreviewImage(page, name, path);
                    break;
                case 2:
                    PreviewSound(page, name, path);
                    break;
                case 0:
                default:
                    DialogHelper.ShowErrorMessage(page, "预览失败，文件可能被加密");
                    break;
            }
        }

        public async static void PreviewImage(Page page, string npkName, string path)
        {
            List<SoftwareBitmap> bitmaps = NPKFile.GetPreviewImagesFromPath(path);
            if (bitmaps.Count > 0)
            {
                List<SoftwareBitmapSource> images = [];
                foreach (var bitmap in bitmaps)
                {
                    var source = new SoftwareBitmapSource();
                    await source.SetBitmapAsync(bitmap);
                    images.Add(source);
                }
                var previewControl = new NPKImagePreviewDialog();
                previewControl.SetImageSources(images);
                DialogHelper.ShowNormalDialog(page, $"预览: {npkName}", previewControl);
            }
            else
            {
                DialogHelper.ShowErrorMessage(page, "未读取到符合条件的可预览图片");
            }
        }

        public async static void PreviewSound(Page page, string npkName, string path)
        {
            Dictionary<string, byte[]> medias = NPKFile.GetPreviewSoundsFromPath(path);
            if (medias.Count > 0)
            {
                var stackPanel = new StackPanel
                {
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    Margin = new Thickness(0,5,0,0),
                    Spacing = 5,
                };
                var scrollViewer = new ScrollViewer
                {
                    Height = 500,
                    Width = 450,
                    Content = stackPanel
                };

                foreach (var media in medias)
                {
                    var title = new TextBlock
                    {
                        Text = media.Key.Replace("/", "_"),
                        HorizontalTextAlignment = TextAlignment.Center
                    };
                    stackPanel.Children.Add(title);

                    var binder = new MediaBinder();
                    binder.Binding += (s, e) =>
                    {
                        try
                        {
                            var ms = new MemoryStream(media.Value);
                            var stream = ms.AsRandomAccessStream();
                            e.SetStream(stream, "audio/ogg");
                        }
                        catch (Exception) {}
                    };
                    MediaSource mediaSource = MediaSource.CreateFromMediaBinder(binder);
                    var player = new MediaPlayerElement
                    {
                        Width = 400,
                        AutoPlay = false,
                        Source = mediaSource,
                        AreTransportControlsEnabled = true,
                    };
                    player.MediaPlayer.Volume = 0.25;
                    var transportControls = player.TransportControls;
                    if (transportControls != null)
                    {
                        transportControls.IsCompact = true;
                        transportControls.IsZoomButtonVisible = false;
                        transportControls.IsZoomEnabled = false;
                    }
                    stackPanel.Children.Add(player);
                }
                await DialogHelper.CreateNormalDialog(page, $"预览: {npkName}", scrollViewer).ShowAsync();
                foreach (var item in stackPanel.Children)
                {
                    if(item is MediaPlayerElement player)
                    {
                        player.MediaPlayer.Pause();
                    }
                }
            }
            else
            {
                DialogHelper.ShowErrorMessage(page, "未读取到可预览音频");
            }
        }
    }
}